<template>
  <a-form
    :model="formData"
    autocomplete="off"
    ref="formRef"
    :label-col="{ style: { width: formLabelWidth } }"
    labelAlign="left"
    class="l-form"
    @finish="handleSubmit"
  >
    <template v-for="item in formClumnData" :key="item.name">
      <a-form-item :rules="item.rules" :label="item.label" :name="item.name">
        <!-- input -->
        <a-input
          v-if="item.type === 'input'"
          @change="throttleFormDataChange(item.name)"
          v-model:value="formData[item.name]"
          :show-count="item.showCount"
          :maxlength="item.maxlength"
          :placeholder="item.placeholder"
          :allowClear="item.allowClear"
          :disabled="item.disabled || confirmLoading"
          :bordered="item.bordered"
        />
        <!-- textarea -->
        <a-textarea
          v-else-if="item.type === 'textarea'"
          @change="throttleFormDataChange(item.name)"
          :auto-size="item.autoSize"
          v-model:value="formData[item.name]"
          :show-count="item.showCount"
          :maxlength="item.maxlength"
          :placeholder="item.placeholder"
          :allowClear="item.allowClear"
          :disabled="item.disabled || confirmLoading"
          :bordered="item.bordered"
        />
        <!-- date-picker -->
        <a-date-picker
          class="l-date-picker"
          v-else-if="item.type === 'date'"
          @change="throttleFormDataChange(item.name)"
          v-model:value="formData[item.name]"
          :format="item.valueFormat"
          :show-time="item.showTime"
          :bordered="item.bordered"
          :valueFormat="item.valueFormat"
          :placeholder="item.placeholder"
          :allowClear="item.allowClear"
          :disabled="item.disabled || confirmLoading"
        />
        <!-- ... -->
        <!-- 其他的组件在用的时候记得追加 -->
        <!-- 插槽 -->
        <!-- 不是默认的简单的就用插槽 -->
        <template v-else-if="item.type === 'slot'">
          <slot
            :name="item.name"
            :item="item"
            :formData="formData"
            :disabled="item.disabled || confirmLoading"
            :formItemChanged="throttleFormDataChange"
          ></slot>
        </template>
      </a-form-item>
    </template>

    <a-form-item v-if="showSubmit" class="l-form-submit-content">
      <a-button html-type="submit" type="primary" :loading="confirmLoading"
        >提交</a-button
      >
    </a-form-item>
  </a-form>
</template>

<script setup name="l-form">
import { onBeforeMount, onUnmounted, reactive, ref, toRefs } from "vue";
import { cloneDeep } from "lodash";
import { throttle } from "/@/utils/tool";

/**
 * 定义组件接收的属性（Props）
 */
const props = defineProps({
  /**
   * 表单列配置数据，一个数组，包含了表单项的配置信息。
   * 类型：数组
   * 默认值：空数组 []
   */
  formClumnData: {
    type: Array,
    default: [],
  },

  /**
   * 表单标签的宽度，用于控制表单域标签的显示宽度。
   * 类型：字符串
   * 默认值："120px"
   */
  formLabelWidth: {
    type: String,
    default: "120px",
  },

  /**
   * 提交按钮加载状态，一般用于表单提交时显示加载动画。
   * 类型：布尔值
   * 默认值：false
   */
  confirmLoading: {
    type: Boolean,
    default: false,
  },

  /**
   * 是否显示提交按钮，用于控制表单底部提交按钮的显隐。
   * 类型：布尔值
   * 默认值：true
   */
  showSubmit: {
    type: Boolean,
    default: true,
  },
});
// emits
/**
 * 定义组件向外触发的事件（Emits）
 */
const emits = defineEmits([
  /**
   * 更新表单列配置数据的事件名。
   * 当内部逻辑修改了表单列配置数据（formClumnData）并且希望通知父组件时，应触发此事件。
   * 参数：新表单列配置数据数组
   */
  "update:formClumnData",

  /**
   * 表单提交事件。
   * 当用户点击提交按钮，执行完相关验证及处理逻辑后，应触发此事件通知父组件表单已被提交。
   * 通常不需要传递参数，除非有特殊需求需要告知父组件额外信息。
   */
  "submit",
  /**
   * 表单发生变化事件。
   * 表单发生变化时触发。
   * 参数：发生变化的表单名 、发生变化的值
   */
  "formChanged",
]);

//state
const formRef = ref(null);
const state = reactive({
  formData: {},
});
const { formData } = toRefs(state);

//methods
/**
 * 定义表单提交处理函数。
 * 当表单提交按钮被点击时，此函数会被调用。
 */
const handleSubmit = () => {
  emits("submit", formData.value);
};
/**
 * 定义表单数据变更处理函数。
 * 当表单中的某个字段值发生变化时，调用此函数来更新 `formClumnData` 中对应项的 `value`。
 * 使用 `cloneDeep` 防止直接修改props，然后查找匹配名称的表单项并更新其值，
 * 最后触发 "update:formClumnData" 事件通知父组件表单项值已变。
 *
 * @param {string} name - 变更的表单项名称。
 */
const formDataChange = (name) => {
  const _formClumnData = cloneDeep(props.formClumnData);
  _formClumnData.find((item) => item.name == name).value = formData.value[name];
  emits("update:formClumnData", _formClumnData);
  emits("formChanged", name, formData.value[name], formData.value);
};
const throttleFormDataChange = throttle(formDataChange, 500);
/**
 * 在组件挂载之前执行的钩子函数。
 * 用于初始化表单数据 `formData`，根据 `formClumnData` 中的每一项配置，
 * 将其初始值赋给 `formData` 的相应属性，以便表单初始显示正确。
 */
onBeforeMount(() => {
  props.formClumnData.forEach((item) => {
    formData.value[item.name] = item.value;
  });
});
/**
 * 组件卸载时执行的钩子函数。
 * 清空 `formData` 的所有值，释放表单数据占用的内存，防止潜在的内存泄漏问题。
 */
onUnmounted(() => {
  formData.value = {};
});

/**
 * 向外暴露表单验证方法
 */
const formValidateFields = (name, cb) => {
  return formRef.value.validateFields(name);
};
/**
 * 向外暴露表单数据方法
 */
const getFormData = () => {
  return cloneDeep(formData.value);
};

defineExpose({
  formValidateFields,
  getFormData,
});
</script>

<style lang="scss" scoped>
.l-form {
  display: flex;
  flex-direction: column;
  overflow: auto;

  .l-form-submit-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    margin-bottom: var(--margin-0);
    align-items: flex-end;
    justify-content: flex-end;
  }
}
</style>
